package com.aidysoft.practice.log;

import com.alibaba.fastjson.JSONObject;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;


import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 系统日志：切面处理类
 */
@Aspect
@Component
public class SysLogAspect {

    @Autowired
    private LogDao logDao;

    private static Logger log = LoggerFactory.getLogger(SysLogAspect.class);
    //spring 开启aop
//    private static final String POINTCUT = "execution(public * service.*.*.*(..)))";
    //指向拦截制定方法的话，可用下边切面表达式（在需要拦截的controller方法上加1OperLog注解，springmvc开aop配置）
    private static final String POINTCUT = "@annotation(com.aidysoft.practice.log.OperLog)";


    //定义切点 @Pointcut
    //在注解的位置切入代码
    @Pointcut(POINTCUT)
    public void logPoinCut() {
    }

    //@Around：环绕通知
    @Around("logPoinCut()")
    public Object saveSysLog(ProceedingJoinPoint proceedingJoinPoint) {

        //获取用户名
        //获取用户ip地址
        // 接收到请求，记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        String filePath = request.getServletContext().getRealPath("log.txt");
        //保存日志
        SysLog sysLog = new SysLog();

        sysLog.setCreateDate(LocalDateTime.now());
        HttpSession session = request.getSession();
        SysPolice sysPolice = (SysPolice) session.getAttribute("currentUser");

        String userId = sysPolice == null ? "0" : sysPolice.getUserId().toString();
        String userName = sysPolice == null ? "未登录用户" : sysPolice.getName();

        sysLog.setName(userName);
        sysLog.setUserId(userId);


        //从切面织入点处通过反射机制获取织入点处的方法
        MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
        //获取切入点所在的方法
        Method method = signature.getMethod();
        //获取操作
        OperLog myLog = method.getAnnotation(OperLog.class);
        if (myLog != null) {
            String value = myLog.message();
            String operation = myLog.operation();
            sysLog.setMessage(value);//保存获取的操作
            sysLog.setOperation(operation);//保存获取的操作
        }
        //获取请求的类名
        String className = proceedingJoinPoint.getTarget().getClass().getName();
        sysLog.setClassName(className);

        //获取请求的方法名
        String methodName = method.getName();
        sysLog.setMethod(methodName);

        //请求的参数
        sysLog.setParams(getArgues(proceedingJoinPoint));


        sysLog.setIp(request.getRemoteAddr());
        sysLog.setUrl(request.getRequestURL().toString());

        Object result = null;
        try {
            result = proceedingJoinPoint.proceed();
            if (result != null) {
                sysLog.setReturnResult(result.toString());
            }
            sysLog.setEndDate(LocalDateTime.now());
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            sysLog.setExceptionMes(throwable.getMessage());
        } finally {
            //打印到控制台
            log.info("{}", sysLog);
            //保存至数据库
            logDao.saveLog(sysLog);

            //写入日志文件
//            FileUtil.writeToFile(filePath,sysLog.toString());
        }
        return result;
    }


    private String getArgues(ProceedingJoinPoint point) {
//        ConcurrentHashMap<String, Object> info = new ConcurrentHashMap<>(3);
        List<ConcurrentHashMap<String, String>> list = new ArrayList<>();
//        info.put("类名", point.getTarget().getClass().getSimpleName());
//        info.put("方法名", point.getSignature().getName());

        String[] parameterNames = ((MethodSignature) point.getSignature()).getParameterNames();
        ConcurrentHashMap<String, String> args = null;

        if (Objects.nonNull(parameterNames)) {
            args = new ConcurrentHashMap<>(parameterNames.length);
            for (int i = 0; i < parameterNames.length; i++) {
                String value = point.getArgs()[i] != null ? point.getArgs()[i].toString() : "null";
                args.put(parameterNames[i], value);
            }
//            info.put("参数", args);
            list.add(args);
        }

        return JSONObject.toJSONString(list);
    }

}
